package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/buffer"
	"go.uber.org/zap/zapcore"
	"os"
)

// myEncoder 自定义日志编码器结构体
// 功能：扩展 zapcore.Encoder 接口，实现自定义日志前缀功能
// 字段说明：
// - zapcore.Encoder: 内嵌原始编码器，保留原有功能
// 通过组合方式扩展编码器，而不是重新实现所有接口方法
type myEncoder struct {
	zapcore.Encoder
}

// EncodeEntry 自定义日志条目编码方法
// 参数说明：
// - entry: 日志条目，包含时间戳、级别、消息等基本信息
// - fields: 额外的字段信息，用于结构化日志
// 返回值：
// - *buffer.Buffer: 包含编码后日志数据的缓冲区
// - error: 编码过程中的错误信息
// 功能：重写编码器的 EncodeEntry 方法，在每条日志前添加自定义前缀
func (m myEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
	// 1. 先调用原始编码器进行基础编码（时间、级别、消息等格式化）
	buff, err := m.Encoder.EncodeEntry(entry, fields)
	if err != nil {
		return buff, err // 如果编码出错，直接返回错误
	}

	// 2. 在原始日志前添加应用标识前缀
	// 从缓冲区中获取当前已格式化的日志内容
	data := buff.String()
	// 清空缓冲区，准备写入新内容
	buff.Reset()
	// 在原始日志内容前添加自定义应用标识前缀，并写回缓冲区
	buff.AppendString("[myApp] " + data)

	return buff, nil
}

// main 函数演示如何实现自定义日志前缀
// 通过创建自定义编码器，可以为所有日志添加统一的应用标识
func main() {
	// 创建日志核心组件
	// zapcore.NewCore 是 zap 的核心构造器，负责日志的编码和输出
	core := zapcore.NewCore(
		// 使用自定义编码器（基于控制台编码器）
		myEncoder{
			Encoder: zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()),
		},
		os.Stdout,         // 日志输出到标准输出（控制台）
		zapcore.InfoLevel, // 设置日志级别为Info及以上（Debug级别日志将被过滤）
	)

	// 创建日志记录器实例
	logger := zap.New(
		core,            // 传入配置好的核心组件
		zap.AddCaller(), // 添加调用者信息（文件名和行号），便于调试定位
	)

	// 记录Info级别的日志
	// 输出格式示例：[myApp] INFO 2023-xx-xx xx:xx:xx ... this is info log
	logger.Info("this is info log")
}
